<?php

namespace Think\Pay\Driver;

class Weixintransfer extends \Think\Pay\Pay {
    
    protected $config = array();

    /**
     * 构建表单
     * @return string
     */
    public function buildRequestForm(\Think\Pay\PayVo $vo) {
        $info['appid'] = $this->config['appid'];
        $info['secret'] = $this->config['secret'];
        $info['return_url'] = $this->config['return_url'];
        $info['notify_url'] = $this->config['notify_url'];
        $info['out_trade_no'] = $vo->getOrderNo();
        $info['total_fee'] = $vo->getFee();
        $info['body'] = $vo->getBody();
        $info['sign'] = $this->makeSign($info);
        $gateway = $this->config['gateway'];
        return $this->_buildForm($info, $gateway);
    }

    /**
     * 签名验证
     * @return boolean
     */
    public function verifyNotify($notify) {
        $this->checkData($notify);
        $match=$notify['sign'] == $this->makeSign($notify);
        if(!$match){
            E('签名不正确');
        }
        return true;
    }

    /**
     * 配置监检测
     */
    public function check() {
        foreach (array('appid', 'secret', 'return_url', 'notify_url', 'gateway') as $key) {
            if (!$this->config[$key]) {
                E("微信支付设置 $key 有误！");
            }
        }
        return true;
    }

    /**
     * 微信远程提交
     * @return array
     */
    public function getRequest() {
        $xml = file_get_contents('php://input') ? : $GLOBALS['HTTP_RAW_POST_DATA'];
        $request = $this->parseXml($xml);
        return $request;
    }

    /**
     * 异步通知成功接收的字符串输出
     */
    function notifySuccess() {
        exit($this->toXml(array(
                    'return_code' => 'SUCCESS',
                    'return_msg' => 'SUCCESS'
        )));
    }

    /**
     * 业务验证
     */
    private function checkData($data) {
        if ('SUCCESS' !== $data['return_code']) {
            E($data['return_msg']);
        }
        if ('SUCCESS' !== $data['result_code']) {
            E($data['err_code'] . ':' . $data['err_code_des']);
        }
    }

    /**
     * 生成签名
     * @return string 
     */
    private function makeSign($param) {
        // 签名步骤一：按字典序排序参数
        ksort($param);
        reset($param);
        $string = $this->toUrlParams($param);
        // 签名步骤二：在string后加入KEY
        $string = $string . "&key=" . ($this->config['key']?:$this->config['secret']);
        // 签名步骤三：MD5加密
        $string = md5($string);
        // 签名步骤四：所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }

    /**
     * 格式化参数格式化成url参数
     * @return string 
     */
    private function toUrlParams($values) {
        $buff = "";
        foreach ($values as $k => $v) {
            if ($k != "sign" && $v != "" && !is_array($v)) {
                $buff .= $k . "=" . $v . "&";
            }
        }

        $buff = trim($buff, "&");
        return $buff;
    }

    /**
     * 将xml转为array
     * @return array 
     */
    private function parseXml($xml = '') {
        if (!$xml) {
            return false;
        }

        libxml_disable_entity_loader(true);
        return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
    }

    /**
     * 输出xml字符
     */
    private function toXml($values) {
        $xml = "<xml>";
        foreach ($values as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }

}
